use crate::common::PI;

const MAXFACTORS: usize = 8;

#[derive(Debug, Clone, Copy)]
pub(crate) struct KissTwiddleCpx {
    pub(crate) r: f32,
    pub(crate) i: f32,
}
pub(crate) struct KissFFT {
    num_fft: usize,
    scale: f32,
    shift: i32,
    factors: [i16; 2*MAXFACTORS],
    bitrev: Vec<i16>,
    twiddles: Vec<KissTwiddleCpx>,
    // arch_fft: arch_fft_state;
}

impl KissFFT {
    pub(crate) fn kiss_fft(&self, input: &[KissTwiddleCpx], output: &mut [KissTwiddleCpx]) {
        for i in 0..self.num_fft {
            output[self.bitrev[i] as usize].r = input[i].r * self.scale;
            output[self.bitrev[i] as usize].i = input[i].i * self.scale;
            // output[self.bitrev[i]].r = SHR32(MULT16_32_Q16(self.scale, input[i].r), scale_shift);
        }

        // self.fft_impl(self, output)
    }
}

impl KissFFT {
    pub(crate) fn new(num_fft: usize) -> Self {

        let mut v = Vec::with_capacity(num_fft);
        let mut i = 0;
        while i < num_fft {
            let phase = ( -2f64 * PI / num_fft as f64 ) * i as f64;
            v.push(KissTwiddleCpx { r: phase.cos() as f32, i: phase.sin() as f32 });
        }
        let mut factors = [0i16; 2 * MAXFACTORS];

        kf_factor(num_fft, &mut factors);

        let mut bitrev = Vec::with_capacity(num_fft);
        compute_bitrev_table(0, &mut bitrev, 1,1, &mut factors);

        KissFFT {
            num_fft,
            scale: 1f32/num_fft as f32,
            shift: -1,
            factors,
            bitrev,
            twiddles: v,
            // arch_fft: arch_fft_init(num_fft),
        }
    }

    pub(crate) fn opus_fft(&self, data: &mut [f32]) {

    }

    pub(crate) fn opus_ifft(&self, data: &mut [f32]) {

    }
}

fn compute_bitrev_table(mut Fout: i16, f: &mut [i16], fstride: i32, in_stride: i32, factors: &mut [i16]) {
    let p=factors[0]; /* the radix  */
    let  m=factors[1]; /* stage's fft length/p */
    let factors = &mut factors[2..];

    if (m==1)
    {
        for j in 0..p{
            f[j as usize] = Fout + j;
        }
    } else {
        for j in 0..p {
            compute_bitrev_table( Fout +  m , &mut f[j as usize..]
                                  , fstride * p as i32, in_stride, factors);
        }
    }
}

fn kf_factor(size: usize, facbuf:&mut[i16; 2*MAXFACTORS])
{
    let mut n = size as i16;
    let mut p = 4i16;
    let mut i = 0;
    let mut stages = 0;
    let nbak = n;

    while n > 1 {
        while n % p != 0 {
            p = match p {
                4 => 2,
                2 => 3,
                _ => p + 2,
            };

            if (p>32000 || p*p > n){
                p = n;          /* no more factors, skip to end */
            }
        }
        n /= p;
        if (p>5){
            println!("prime factor too large: {}", p)
        }

        facbuf[2*stages] = p;
        if (p==2 && stages > 1)
        {
            facbuf[2*stages] = 4i16;
            facbuf[2] = 2i16;
        }
        stages += 1;

    }

    for i in 0..stages/2 {
        let tmp = facbuf[2*i];
        facbuf[2*i] = facbuf[2*(stages-i-1)];
        facbuf[2*(stages-i-1)] = tmp;
    }

    n = nbak;
    for i in 0..stages {
        n = n / facbuf[2 * i];
        facbuf[2 * i] = n;
    }
}